﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MiscUtils.cs" company="" />
// <summary>
//   Misc utilities.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Utilities
{
    using System;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;

    /// <summary>
    /// Misc utilities.
    /// </summary>
    public static class MiscUtils
    {
        /// <summary>
        /// Decides if the given object is <see cref="XElement"/> or <see cref="XAttribute"/> and executes the given action using it.
        /// If the given XML object is neither - executes nothing.
        /// </summary>
        /// <param name="executingXmlObject">The <see cref="XObject"/> to use with the given delegate.</param>
        /// <param name="elementWorker">The action to take with an <see cref="XElement"/>.</param>
        /// <param name="attributeWorker">The action to take with an <see cref="XAttribute"/></param>
        public static void ExecuteOnXmlObject(XObject executingXmlObject, Action<XElement> elementWorker, Action<XAttribute> attributeWorker)
        {
            var element = executingXmlObject as XElement;

            if (element != null)
            {
                elementWorker(element);

                return;
            }

            var attribute = executingXmlObject as XAttribute;

            if (attribute != null)
            {
                attributeWorker(attribute);
            }
        }

        /// <summary>
        /// Retrieves the value of the given XML element, without the value of its child elements.
        /// </summary>
        /// <param name="element">The XML element to retrieve the value for.</param>
        /// <returns>The value of just the element, without that which is of its child elements.</returns>
        public static string GetElementSingleValue(XElement element)
        {
            string elementValue = element.Value;

            if (element.Elements().Any())
            {
                string childValue = element.Elements().First().Value;
                int childIndex = elementValue.IndexOf(childValue, StringComparison.Ordinal);
                elementValue = elementValue.Substring(0, childIndex);
            }

            return elementValue;
        }

        /// <summary>
        /// Adjusts the given string so it can be compared using a specific scheme of ignoring case and/or ignoring white-spaces.
        /// </summary>
        /// <param name="input">The string to convert.</param>
        /// <param name="toLower">Whether to transform the input to lower case (for a case-ignoring comparison).</param>
        /// <param name="removeWhiteSpaces">Whether to eliminate all white-spaces from the input string (for a white-spaces ignoring comparison)</param>
        /// <returns>The adjusted string.</returns>
        public static string AdjustCaption(string input, bool toLower, bool removeWhiteSpaces)
        {
            if (!toLower && !removeWhiteSpaces)
            {
                return input;
            }

            var resultEnumeration = input.Select(
                ch => removeWhiteSpaces && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
                          ? default(char)
                          : toLower && Char.IsLetter(ch)
                                ? Char.ToLower(ch)
                                : ch);

            var result = new StringBuilder();
            foreach (var ch in resultEnumeration)
            {
                if (ch != default(char))
                {
                    result.Append(ch);
                }
            }

            return result.ToString();
        }

        /// <summary>
        /// Adjusts the given XName so it can be compared using a specific scheme of ignoring case and/or ignoring white-spaces.
        /// The adjustments are done both on the local-name and the namespace.
        /// </summary>
        /// <param name="input">The XName to convert.</param>
        /// <param name="toLower">Whether to transform the input to lower case (for a case-ignoring comparison).</param>
        /// <param name="removeWhiteSpaces">Whether to eliminate all white-spaces from the input XName (for a white-spaces ignoring comparison)</param>
        /// <returns>The adjusted XName.</returns>
        public static XName AdjustCaption(XName input, bool toLower, bool removeWhiteSpaces)
        {
            return XName.Get(
                AdjustCaption(input.LocalName, toLower, removeWhiteSpaces),
                AdjustCaption(input.NamespaceName, toLower, removeWhiteSpaces));
        }
    }
}
